package com.atguigu.gmall.search.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.search.entity.Goods;
import com.atguigu.gmall.search.repository.GoodsRepository;
import com.atguigu.gmall.search.service.SearchService;
import com.atguigu.gmall.search.vo.SearchParamVo;
import com.atguigu.gmall.search.vo.SearchRespVo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    GoodsRepository goodsRepository;
    @Autowired
    ElasticsearchRestTemplate restTemplate;
    @Override
    public void updateHotScore(Long skuId, Long score) {
        Document document = Document.create();
        document.append("hotScore",score);

        UpdateQuery query = UpdateQuery.builder("" + skuId)
                .withDocAsUpsert(true)
                .withDocument(document).build();
        restTemplate.update(query, IndexCoordinates.of("goods"));
    }

    @Override
    public void deleteGoods(Long skuId) {
        goodsRepository.deleteById(skuId);
    }

    @Override
    public void saveGoods(Goods goods) {
        goodsRepository.save(goods);
    }

    @Override
    public SearchRespVo search(SearchParamVo vo) {
        //1.检索条件
        Query query = buildSearchDSL(vo);
        //2.搜索 分析
        SearchHits<Goods> hits = restTemplate.search(query, Goods.class, IndexCoordinates.of("goods"));
        //3.处理结果
        SearchRespVo result = buildSearchResp(hits,vo);
        return result;
    }



    //根据前端传递的检索条件 构建es用的DSL
    private Query buildSearchDSL(SearchParamVo vo) {
        //===============1.构建查询条件========
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //根据前端传过来的参数情况 动态构建出这个DSL
        //分类条件

        if (vo.getCategory3Id() != null) {
            TermQueryBuilder category3IdQuery = QueryBuilders.termQuery("category3Id", vo.getCategory3Id());
            boolQuery.must(category3IdQuery);
        }
        if (vo.getCategory2Id()!=null) {
            TermQueryBuilder category2IdQuery = QueryBuilders.termQuery("category2Id", vo.getCategory2Id());
            boolQuery.must(category2IdQuery);
        }
        if (vo.getCategory1Id()!=null) {
            TermQueryBuilder category1IdQuery = QueryBuilders.termQuery("category1Id", vo.getCategory1Id());
            boolQuery.must(category1IdQuery);
        }

        //=====模糊检索=====
        if (!StringUtils.isEmpty(vo.getKeyword())) {
            boolQuery.must(QueryBuilders.matchQuery("title",vo.getKeyword()));
        }

        //=====品牌检索=====
        if (!StringUtils.isEmpty(vo.getTrademark())) {
            long tmId = Long.parseLong(vo.getTrademark().split(":")[0]);
            boolQuery.must(QueryBuilders.termQuery("tmId",tmId));
        }

        //=====属性检索======

        if (vo.getProps()!=null && vo.getProps().length>0) {
            for (String prop : vo.getProps()) {
                //4:机身存储
                String[] split = prop.split(":");
                long attrId = Long.parseLong(split[0]);
                String attrValue = split[1];
                //查询条件
                BoolQueryBuilder bool = QueryBuilders.boolQuery();
                bool.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                bool.must(QueryBuilders.termQuery("attrs.attrValue",attrValue));
                //嵌入式
                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", bool, ScoreMode.None);
                boolQuery.must(nestedQuery);
            }
        }

        //=========以上【检索】条件完成=======
        //0、原生DSL
        NativeSearchQuery dsl = new NativeSearchQuery(boolQuery);

        //=========排序=======
        //order=1:asc
        if (!StringUtils.isEmpty(vo.getOrder())) {
            String[] split = vo.getOrder().split(":");
            String type = split[0]; //排序的类型
            String order =split[1];//顺序

            String orderField = "";
            switch (type){
                case "1":
                    orderField = "hotScore";
                    break;
                case "2":
                    orderField = "price";
                    break;
                default:
                    orderField = "hotScore";
            }
            //根据前端参数得到排序条件
            Sort.Direction direction = Sort.Direction.ASC;
            try {
                direction = Sort.Direction.fromString(order);
            }catch (Exception e){}
            Sort sort = Sort.by(direction, orderField);
            dsl.addSort(sort);
        }


        //=====分页======
        if (vo.getPageNo()!=null && vo.getPageNo()>0) {
            Pageable pageable = PageRequest.of(vo.getPageNo()-1, RedisConst.PAGE_SIZE);
            dsl.setPageable(pageable);
        }

        //========高亮条件==========
        if(!StringUtils.isEmpty(vo.getKeyword())){
            HighlightBuilder builder = new HighlightBuilder();
            builder.field("title").preTags("<span style='color:red'>").postTags("</span>");

            HighlightQuery highlightQuery = new HighlightQuery(builder);
            dsl.setHighlightQuery(highlightQuery);
        }



        //====品牌聚合分析=====
        TermsAggregationBuilder tmIdAgg = AggregationBuilders.terms("tmIdAgg")
                .field("tmId")
                .size(100);
        TermsAggregationBuilder tmNameAgg = AggregationBuilders.terms("tmNameAgg").field("tmName").size(1);
        tmIdAgg.subAggregation(tmNameAgg);

        TermsAggregationBuilder tmLogoAgg = AggregationBuilders.terms("tmLogoAgg").field("tmLogoUrl").size(1);
        tmIdAgg.subAggregation(tmLogoAgg);
        dsl.addAggregation(tmIdAgg);
        //====属性聚合分析=====
        NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg", "attrs");
        //attrId聚合
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg").field("attrs.attrId").size(100);
        //attrName聚合
        TermsAggregationBuilder attrNameAgg = AggregationBuilders.terms("attrNameAgg").field("attrs.attrName").size(1);
        attrIdAgg.subAggregation(attrNameAgg);
        //attrValue聚合
        TermsAggregationBuilder attrValueAgg = AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue").size(100);
        attrIdAgg.subAggregation(attrValueAgg);

        attrAgg.subAggregation(attrIdAgg);
        dsl.addAggregation(attrAgg);

        //Cloud Native 云原生
        return dsl;
    }
}
